package com.bjmashibing.system.huawei;



import com.bjmashibing.system.huawei.buf_recv.Cbuffer_machine;
import com.bjmashibing.system.huawei.domain.BufferInfo;
import com.bjmashibing.system.huawei.domain.DataInfo;
import com.bjmashibing.system.huawei.service.MyComp;
import com.bjmashibing.system.huawei.service.TaskService;
import com.bjmashibing.system.huawei.vivo.Messaging;
import com.bjmashibing.system.huawei.vivo.xiaomi_push;
import com.bjmashibing.system.test_xiaomi;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;

import com.bjmashibing.system.huawei.oppo.oppo_push;
import com.bjmashibing.system.huawei.vivo.vivo_push;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

import static com.bjmashibing.system.huawei.service.TaskService.get_ip_prot;
import static com.bjmashibing.system.huawei.service.TaskService.handle_cmd;

import static java.lang.Thread.sleep;
import com.bjmashibing.system.test_xiaomi;

@EnableAsync  //开启异步注解功能
@EnableScheduling //开启基于注解的定时任务
@SpringBootApplication
public class SocketNIO {
    public static int DEFAULT_PORT = 9501;




    private final static Logger logger = LoggerFactory.getLogger(SocketNIO.class);



    private    static    final    int            BUF_SIZE =            1024;
    private    static    final    int            PORT =            9501;
    private    static    final    int            TIMEOUT =            3000;



    public static void main(String[] args) throws Exception {
        SpringApplication.run(SocketNIO.class, args);


        logger.debug("print debug message.");
        logger.info("print info message.");
        logger.error("print trace message.");

        Cbuffer_machine.buffer_init();

        ByteBuffer buffer = ByteBuffer.allocate(1024);
        for (int i = 0; i < 100; i++) {
            DataInfo dataInfo = new DataInfo();
            dataInfo.setBuffer_data(buffer);
            dataInfo.setIp_port_data("");

            BufferInfo bufferInfo = new BufferInfo();
            bufferInfo.setDataInfo(dataInfo);
            bufferInfo.setbUsed(false);
            static_var.buffer_2[i] = bufferInfo;


        }
        MyComp.mo.excutVoidTask111();



         try{
            static_var.database_to_map();
        }
        catch(Exception e){
            logger.info("main,error=",e);
            e.printStackTrace();
        }
        //        logger.info("database_to_map,static_var.map_token=" + static_var.map_token.toString());
        int nums_main = 0;
        boolean flag_1 = true;
        Selector selector =   null;
        ServerSocketChannel ssc = null;
        while (true) {
            sleep(3000);
            if (static_var.map_socket.size() > 0) {
                for(SocketChannel value : static_var.map_socket.values()){
                    if (value != null) {
                        value.socket().close();
                        value.close();
                        value = null;
                    }
                }
            }

            logger.info("main,while,nums_main=" + nums_main);
            try {
                if(selector !=  null ) {
                    logger.info("aaa6...");
                    selector.close();
                    selector =   null;
                }
                if  (ssc != null ) {
                    logger.info("aaa7...");
                    ssc.close();
                    ssc = null;
                }
            } catch  (Exception e) {
                flag_1 = false;
                logger.info("error,aaa5...=",e);
                e.printStackTrace();
            }
            try {
                selector = Selector.open();
                ssc = ServerSocketChannel.open();
                ssc.socket().bind( new InetSocketAddress(PORT));
                ssc.configureBlocking( false  );
//                ssc.setOption(StandardSocketOptions.SO_KEEPALIVE, Boolean.TRUE)
//                        .setOption(StandardSocketOptions.TCP_NODELAY, Boolean.TRUE);
                ssc.register(selector, SelectionKey.OP_ACCEPT);
                flag_1 = true;
                while ( flag_1 ) {
                    if  (selector.select(TIMEOUT) == 0 ) {
//                        logger.info("aaa1...");
                        continue;
                    }
                    Set<SelectionKey> keys = selector.selectedKeys();
                    boolean flag = keys.isEmpty();
                    int size = keys.size();
//                    logger.info("size1 =" + size);
                    try{

                        if (size > 0) {
                            if (!flag) {
                                for(SelectionKey key:keys){
//                                    logger.info("size2 =" + size);
                                    if (key == null) {
                                        logger.info("aaa2...");
                                        continue;
                                    }
                                    if(key.isAcceptable()) {
                                        handleAccept(key);
                                    }
                                    if(key.isReadable()) {
                                        handleRead(key);
                                    }
                                    if (key.isConnectable()) {
                                        logger.info("isConnectable = true");
                                    }
                                }
                                keys.clear();
                            }
                        }

                    }catch(Exception e){
                        flag_1 = false;
                        logger.info("error,aaa3...=",e);
                        boolean flag_temp = keys.isEmpty();
                        if (size > 0) {
                            if (!flag_temp) {
                                keys.clear();
                            }
                        }
                    }
                }

            } catch  (Exception e) {
                flag_1 = false;
                logger.info("error,aaa4...=",e);
                e.printStackTrace();

            } finally {
                logger.info("run,finally...");
                flag_1 = false;
                try {
                    if(selector !=  null ) {
                        logger.info("aaa6...");
                        selector.close();
                        selector =   null;
                    }
                    if  (ssc != null ) {
                        logger.info("aaa7...");
                        ssc.close();
                        ssc = null;
                    }
                } catch  (Exception e) {
                    flag_1 = false;
                    logger.info("error,aaa5...=",e);
                    e.printStackTrace();
                }
            }
            logger.info("run,finally2...");
            flag_1 = false;

        }







        /*String alias1 = "1JC/eDRYxjPSYfI0l3heX8GhoBMcfGar8QXzEt6H0pqP6TX9ujw8WigknprWj+ZN";
        try {
            xiaomi_push.sendMessageToAlias3(alias1,"全局布防","861232323;|3400 00 000]","861232323","|3400 00 000]");
        } catch (Exception e) {
            logger.info("main,error=",e);
            e.printStackTrace();
        }
        String alias2 = "Rd+PhKWfvifEGq5upVKF5bPCN0SjCxuBgGMaVdHXN5pV59Pr6vA/VantVobp1nZL";
        try {
            xiaomi_push.sendMessageToAlias3(alias2,"全局布防","861232323;|3400 00 000]","861232323","|3400 00 000]");
        } catch (Exception e) {
            logger.info("main,error=",e);
            e.printStackTrace();
        }


        try {
            String regId = "CN_a813bde520a0cf430007a023f4850e0f";
            oppo_push.send_message_oppo_to_regid(regId,"火警",
                    "[" + "8612345678" + ":" + "|1110 00 000]","8612345678","|1110 00 000]");
        } catch (Exception e) {
            logger.info("main,error=",e);
            e.printStackTrace();
        }

        try {
            vivo_push.send_message_vivo_to_regid("16074818390129431589891","全局佈防",
                    "[" + "8612345678" + ":" + "|3400 00 000]","8612345678","|3400 00 000]");
        } catch (Exception e) {
            logger.info("main,error=",e);
            e.printStackTrace();
        }*/



        /*try {
            Messaging.send_message_fcm_to_regid("16074818390129431589891","全局佈防",
                    "[" + "8612345678" + ":" + "|3400 00 000]","8612345678","|3400 00 000]");
        } catch (Exception e) {
            logger.info("samsung push error=" + e.getMessage());
            e.printStackTrace();
        }*/




//        PushNcMsg.refreshToken();

        /*String str_token = "IQAAAACy0Z4gAABC6E0Ku4esIIYlCu48vvDtw4rjqov-q_MXpPfC3dtWAWC7XQIO72VwaY_SX-W8mjV8XDUEtSo45vqroyS6YI2EK4DGvpy5cvCxsw";

        try {
            static_var.push_huawei_obj.huawei_initialize_app();
            static_var.push_huawei_obj.sendNotification2(str_token,"全局布防","861232323;|3400 00 000","861232323","|3400 00 000]");
        } catch (Exception e) {
            logger.info("main,error=",e);
            e.printStackTrace();
        }*/
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }
    public    static void    handleAccept(SelectionKey key)            throws            IOException {

        ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel();





        SocketChannel sc = ssChannel.accept();

        sc.configureBlocking(                false        );

        sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocateDirect(BUF_SIZE));


        String ip = sc.socket().getInetAddress().toString();
        if (ip.contains("/")) {
            ip = ip.substring(1);
        }
        if (!ip.equals("43.130.3.36")) {
            logger.info("isAcceptable,ip=" + ip);
            return;
        }
        String ip_port = get_ip_prot(sc);
        logger.info("isAcceptable,ip_port=" + ip_port);
        static_var.map_socket.clear();
        Cmd_fun.ip_port = ip_port;
        static_var.map_socket.put(ip_port,sc);
       /* if (!static_var.map_socket.containsKey(ip_port)) {
            static_var.map_socket.put(ip_port,sc);
        }else{
            static_var.map_socket.remove(ip_port);
            static_var.map_socket.put(ip_port,sc);
        }*/

    }


    public    static void    handleRead(SelectionKey key)            throws            IOException {
        SocketChannel sc = (SocketChannel) key.channel();
        String ip = sc.socket().getInetAddress().toString();
        if (ip.contains("/")) {
            ip = ip.substring(1);
        }
//                        logger.info("isReadable,ip=" + ip);
//        Cmd_fun.ip_port = get_ip_prot(sc);
        if (!ip.equals("43.130.3.36")) {
//            logger.info("isReadable,ip=" + ip);
            return;
        }

        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.clear();
        int readBytes = sc.read(buffer);
        if(readBytes>0){
//            logger.info("handleRead，readBytes=" +readBytes );
            buffer.flip();
            byte[] array_temp = new byte[1460];


                if ((buffer.position() > 1460) || (buffer.position() > buffer.limit())) {
                    logger.info("error,handleRead,buffer.position=" + buffer.position());
                    return;
                }
                if (buffer.remaining() < 1) {
                    logger.info("error,handleRead,buffer.position=" + buffer.position());
                    return;
                }
                buffer.get(array_temp, 0, buffer.limit());//


            Cbuffer_machine.buffer_save(buffer.limit(), array_temp);


            /*DataInfo dataInfo = new DataInfo();
            dataInfo.setBuffer_data(buffer);
            dataInfo.setIp_port_data(ip_port);

            BufferInfo bufferInfo = new BufferInfo();
            bufferInfo.setDataInfo(dataInfo);
            bufferInfo.setbUsed(true);
            for (int i = 0; i < 100; i++) {
                if(!static_var.buffer_2[i].isbUsed()){
                    static_var.buffer_2[i] = bufferInfo;
                }
            }*/

        }
    }









    public    static void    handleWrite(SelectionKey key)    throws   IOException {
        ByteBuffer buf = (ByteBuffer) key.attachment();
        buf.flip();
        SocketChannel sc = (SocketChannel) key.channel();
        while
        (buf.hasRemaining()) {
            sc.write(buf);
        }
        buf.compact();
    }
    /**
     * http重定向到https
     *
     * @return
     */
    @Bean
    public TomcatServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint constraint = new SecurityConstraint();
                constraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                constraint.addCollection(collection);
                context.addConstraint(constraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(httpConnector());
        return tomcat;
    }
    @Bean
    public Connector httpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        //Connector监听的http的端口号
        connector.setPort(8081);
        connector.setSecure(false);
        //监听到http的端口号后转向到的https的端口号
        connector.setRedirectPort(443);
        return connector;
    }






}
